
#ifndef _ka_system_event_h
#define _ka_system_event_h

#include "ka-system/thread.h"
#include "ka-system/uuid.h"

namespace ka {
    
    /**
     * Low-level system event
     */
    class Event {
	public:
		enum {
            EXTRA_EMPTY,
            EXTRA_FLOAT,
            EXTRA_UINT
        };
        
        Event()
		: action(0) {}
        
		void clear();
        
        uint32_t action;
        
        int getExtraType(int extraNum) const;
        int getExtraCount() const;
        float getFloatExtra(int extraNum) const;
        uint32_t getUIntExtra(int extraNum) const;
        
    private:
        struct _Arg {
            union {
                float f;
                uint32_t ui;
            } u;
            float asFloat() const;
            uint32_t asUInt() const;
            void clear();
            
            uint32_t type;
        };
        
        _Arg _defExtra[4];
        _Arg *_dynExtra;
        int _extraCount;
    };
	
    class IEventHook {
	public:
		virtual ~IEventHook();
		virtual void onEvent(const Event &e) = 0;
	};
    
    class EventHandler {
    public:
        EventHandler(const UUID &eventUid);
        ~EventHandler();
        void handleEvent(const Event &e);
        void removeFromContext();
        const UUID &getEventUid() const;
        EventHandler *getNext() const;
        void setEventHook(IEventHook *hook);
    private:
        UUID _eventUid;
        class Context *_context;
        IEventHook *_hook;
        EventHandler *_next;
        EventHandler *_prev;
    };
    
    class EventRaiser {
    public:
        EventRaiser(const UUID &eventUid);
        void raiseEvent(const Event &e);
    private:
        UUID _eventUid;
        class Context *_context;
        int _cachedEventSlot;
    };
        
	class IEventReceiver {
	public:
		virtual ~IEventReceiver();
		virtual bool receiveEvent(Event &out, uint64_t timeoutMillis) = 0;
	};
    
    class IEventPoster {
    public:
        virtual ~IEventPoster();
        virtual bool postEvent(const Event &in) = 0;
    };
    
    class EventQueue : public IEventPoster, public IEventReceiver {
    public:
        EventQueue(uint32_t eventLimit);
        virtual ~EventQueue();
        virtual bool receiveEvent(Event &out, uint64_t timeoutMillis);
        virtual bool postEvent(const Event &in);
    private:
        Mutex _lock;
        Event *_events;
        uint32_t _limit;
        uint32_t _write;
        uint32_t _read;
        uint32_t _count;
    };
}

#endif